﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Reflection.Emit;
using System.IO;
using System.Xml;
using System.Collections;
using System.Threading;

namespace PServiceBus.Serializer.Xml {
    public static partial class Generator {

        const int DefaultStringBuilderCapacity = 1024 * 2;

        const TypeAttributes TypeAttribute =
            TypeAttributes.Public | TypeAttributes.Serializable | TypeAttributes.Sealed;

        const BindingFlags PropertyBinding = BindingFlags.Instance | BindingFlags.Public;

        const BindingFlags MethodBinding = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;

        const MethodAttributes MethodAttribute =
            MethodAttributes.Public
            | MethodAttributes.Virtual
            | MethodAttributes.Final
            | MethodAttributes.HideBySig
            | MethodAttributes.NewSlot
            | MethodAttributes.SpecialName;

        
        static readonly char _quoteChr = '`';
        const string Less = "<", Greater = ">", CloseTag = "</", Space = " ", Equal = " = ", Quote  = "\"",
            EndTag = "/>", QuoteChar = "`", ItemsStr = "Items",
            XmlSerializerStr = "XmlSerializer",
              ClassStr = "Class", _dllStr = ".dll",
              IListStr = "IList`1",
              IDictStr = "IDictionary`2",
              XmlSerializeStr = "IXmlSerializer.Serialize",
              XmlDeserializeStr = "IXmlSerializer.Deserialize",
              SerializeStr = "Serialize", DeserializeStr = "Deserialize",
              WriteStr = "Write", ReadStr = "Read", ArrayLiteral = "[]",
              ReadPropertyStr = "ReadProperty",
              ArrayStr = "Array", AnonymousBracketStr = "<>",
              TypeStr = "type", NilStr = "nil", StrStr = "str",
              ItemStr = "Item", DictStr = "dict", KeyStr = "Key", ValueStr = "Value",
              AddStr = "Add",
              SetItemStr = "set_Item",
              ToArrayStr = "ToArray";
        static readonly Type _objectType = typeof(Object),
            _serializerType = typeof(IXmlSerializer<>),
            _stringType = typeof(String),
            _stringBuilderType = typeof(StringBuilder),
            _voidType = typeof(void),
            _intType = typeof(int),
            _boolType = typeof(bool),
            _xmlReaderExType = typeof(XmlReaderEx),
            _nullableType = typeof(Nullable<>),
            _dateTimeType = typeof(DateTime),
            _timeSpanType = typeof(TimeSpan),
            _decimalType = typeof(decimal),
            _guidType = typeof(Guid),
            _byteArrayType = typeof(byte[]),
            _listType = typeof(IList),
            _dictType = typeof(IDictionary),
            _genericDictType = typeof(Dictionary<,>),
            _genericListType = typeof(List<>),
            _genericKeyValuePairType = typeof(KeyValuePair<,>),
            _genericDictionaryEnumerator =
                Type.GetType("System.Collections.Generic.Dictionary`2+Enumerator"),
            _genericListEnumerator =
                Type.GetType("System.Collections.Generic.List`1+Enumerator"),
            _typeType = typeof(Type),
            _generatorType = typeof(Generator);
        static readonly MethodInfo _stringBuilderToString =
            _stringBuilderType.GetMethod("ToString", Type.EmptyTypes),
            _stringBuilderAppend = _stringBuilderType.GetMethod("Append", new[] { _stringType }),
            _stringBuilderClear = _stringBuilderType.GetMethod("Clear"),
            _stringOpEquality = _stringType.GetMethod("op_Equality", MethodBinding),
            _iDisposableDispose = typeof(IDisposable).GetMethod("Dispose"),
            _generatorGetWriteString = _generatorType.GetMethod("GetWriteString", MethodBinding),
            _generatorHasNilAttribute = _generatorType.GetMethod("HasNilAttribute", MethodBinding),
            _generatorGetStringBuilder = _generatorType.GetMethod("GetStringBuilder", MethodBinding),
            _generatorWriteStartTag = _generatorType.GetMethod("WriteStartTag", MethodBinding),
            _generatorWriteEndTag = _generatorType.GetMethod("WriteEndTag", MethodBinding),
            _generatorWriteStartWithAttributeTag = _generatorType.GetMethod("WriteStartWithAttributeTag", MethodBinding),
            _generatorIsNodeEnd = _generatorType.GetMethod("IsNodeEnd", MethodBinding),
            _generatorIsNodeValid = _generatorType.GetMethod("IsNodeValid", MethodBinding),
            _generatorWriteObject = _generatorType.GetMethod("WriteObject", MethodBinding),
            _generatorReadObject = _generatorType.GetMethod("ReadObject", MethodBinding),
            _generatorFix = _generatorType.GetMethod("Fix", MethodBinding),
            _generatorReadToEndElement = _generatorType.GetMethod("ReadToEndElement", MethodBinding),
            _generatorGetName = _generatorType.GetMethod("GetName", MethodBinding),
            _xmlReaderExRead = _xmlReaderExType.GetMethod("Read"),
            _xmlReaderExElementName = _xmlReaderExType.GetProperty("ElementName").GetGetMethod();
        static readonly ConstructorInfo _stringBuilderCtor =
            _stringBuilderType.GetConstructor(new[] { typeof(int) }),
            _xmlReaderExCtor = _xmlReaderExType.GetConstructor(new [] { _stringType });
        static readonly Type[] _stringParamTypes = new[] { _stringType };

        static readonly ConcurrentDictionary<Type, Type> _types =
            new ConcurrentDictionary<Type, Type>();
        static readonly ConcurrentDictionary<string, MethodBuilder> _writeMethodBuilders =
            new ConcurrentDictionary<string, MethodBuilder>();

        static readonly ConcurrentDictionary<int, ConcurrentDictionary<string, MethodInfo>> _readMethodBuildersThread =
            new ConcurrentDictionary<int, ConcurrentDictionary<string, MethodInfo>>();


        static ConcurrentDictionary<string, MethodInfo> _readMethodBuilders {
            get {
                var threadID = Thread.CurrentThread.ManagedThreadId;
                return _readMethodBuildersThread.GetOrAdd(threadID, key => {
                    return new ConcurrentDictionary<string, MethodInfo>();
                });
            }
        }
        

       
        static readonly ConcurrentDictionary<int, ConcurrentDictionary<string, MethodInfo>> _readPropertyMethodBuildersThread =
            new ConcurrentDictionary<int, ConcurrentDictionary<string, MethodInfo>>();


        static ConcurrentDictionary<string, MethodInfo> _readPropertyMethodBuilders {
            get {
                var threadID = Thread.CurrentThread.ManagedThreadId;
                return _readPropertyMethodBuildersThread.GetOrAdd(threadID, key =>
                {
                    return new ConcurrentDictionary<string, MethodInfo>();
                });
            }
        }

        static readonly ConcurrentDictionary<Type, bool> _primitiveTypes =
            new ConcurrentDictionary<Type, bool>();

        static readonly ConcurrentDictionary<Type, IEnumerable<PropertyInfo>> _typeProperties =
            new ConcurrentDictionary<Type, IEnumerable<PropertyInfo>>();
        static readonly ConcurrentDictionary<int, StringBuilder> _stringBuilders =
            new ConcurrentDictionary<int, StringBuilder>();
        static readonly ConcurrentDictionary<string, string> _fixes =
            new ConcurrentDictionary<string, string>();
    }
}
